Add tap controls; refactor AC_branches.jl - #239
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors transformer tap handling by moving tap control behavior into the native branch construction path (gated by an enable_controls attribute and per-circuit TransformerControlObjective), while reorganizing/renaming related tests and tightening network-reduction “irreducible bus” logic for controlled devices and outages.
Changes:
- Add tap-control variable/constraint plumbing to the native AC/DC branch models (including new voltage- and reactive-flow control constraints).
- Restructure and expand transformer tap tests into separate “fixed tap” vs “controls” suites; remove legacy/disabled tap-control test files.
- Refactor irreducible-bus selection to incorporate outage-monitored/outaged components and controllable transformers.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test_voltage_control_tap_models.jl | Removes legacy VoltageControlTap model tests. |
| test/test_transformer_fixed_tap.jl | Adds fixed (off-nominal) tap physics tests across native models. |
| test/test_transformer_controls.jl | Adds transformer control-objective tests (tap variables + control bands). |
| test/test_power_flow_in_the_loop.jl | Removes commented PhaseShiftingTransformer PFitL test block. |
| test/test_postcontingency_mixed_outage_axes.jl | Updates outage pinning test to call the new helper. |
| test/test_native_transformer_tap.jl | Removes older fixed-tap + coefficient ground-truth tests (now relocated). |
| test/test_native_tapcontrol.jl | Removes disabled TapControl formulation tests. |
| test/test_native_network_reductions.jl | Removes commented PhaseAngleControl and tap regulated-bus error test blocks. |
| test/test_native_lpacc_model.jl | Re-enables/updates LPACC shunt validation gate test. |
| test/test_native_dcp_acp_models.jl | Re-enables use_slacks validation test for StaticBranchUnbounded. |
| test/test_device_branch_constructors.jl | Removes commented phase-shifting DC power flow test block. |
| test/runtests.jl | Removes DISABLED_TESTS entries (now empty). |
| test/Project.toml | Removes PowerFlows from test deps/sources (but tests still reference it). |
| test/includes.jl | Comments out using PowerFlows and const PFS = PowerFlows (but tests still reference PFS). |
| src/PowerOperationsModels.jl | Exports ReactivePowerFlowControlConstraint. |
| src/network_models/instantiate_network_model.jl | Refactors irreducible-bus selection; adds outage + controllable-transformer pinning. |
| src/core/network_formulations.jl | Removes old regulated-voltage/tap-current-form traits. |
| src/core/constraints.jl | Adds ReactivePowerFlowControlConstraint type. |
| src/ac_transmission_models/voltage_control_tap_models.jl | Removes legacy VoltageControlTap formulation implementation. |
| src/ac_transmission_models/branch_constructor.jl | Wires new tap-control variables/constraints into branch construction stages. |
| src/ac_transmission_models/AC_branches.jl | Implements tap-control variables, voltage/reactive control constraints, and tap-aware flow equations. |
Suppressed comments (3)
test/includes.jl:39
PFSis still referenced by active tests (e.g.test/test_power_flow_in_the_loop.jl), but the alias is commented out. This will raiseUndefVarError: PFS not definedat runtime.
const PSY = PowerSystems
const POM = PowerOperationsModels
const IOM = InfrastructureOptimizationModels
#const PFS = PowerFlows
const PSB = PowerSystemCaseBuilder
const PNM = PowerNetworkMatrices
test/Project.toml:23
PowerFlowsis removed from[deps], but multiple active tests (not just commented blocks) still rely on it via thePFSalias (seetest/test_power_flow_in_the_loop.jl). This will fail to instantiate the test environment.
This issue also appears on line 34 of the same file.
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
ParallelTestRunner = "d3525ed8-44d0-4b2c-a655-542cee43accc"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd"
PowerOperationsModels = "bed98974-b02a-5e2f-9ee0-a103f5c450dd"
PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
test/Project.toml:40
PowerFlowsis removed from[sources], but it’s still required by the active PFitL tests. Without a source entry (when using custom git sources for the other Sienna packages), resolving the test environment may pull an incompatible version or fail outright.
[sources]
InfrastructureOptimizationModels = {rev = "main", url = "https://github.com/Sienna-Platform/InfrastructureOptimizationModels.jl"}
InfrastructureSystems = {rev = "IS4", url = "https://github.com/Sienna-Platform/InfrastructureSystems.jl"}
PowerNetworkMatrices = {rev = "psy6", url = "https://github.com/Sienna-Platform/PowerNetworkMatrices.jl"}
PowerSystemCaseBuilder = {rev = "psy6", url = "https://github.com/Sienna-Platform/PowerSystemCaseBuilder.jl"}
PowerSystems = {rev = "psy6", url = "https://github.com/Sienna-Platform/PowerSystems.jl"}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| function _validate_controlled_branch_not_reduced( | ||
| network_model::NetworkModel, | ||
| devices::IS.FlattenIteratorWrapper{T}, | ||
| formulation_name::String, | ||
| ::Type{T}, | ||
| controlled_names, | ||
| ) where {T <: PSY.ACTransmission} |
There was a problem hiding this comment.
transformer_models.jl isn't used. I will remove it when I implement phase shifting.
I believe a parallel merge is the only merge that can happen; series merges are blocked by specifying irreducible buses.
| for circuit in PSY.get_circuits(transformer) | ||
| _control_enabled(circuit) || continue | ||
| _push_component_buses!(irreducible_buses, circuit) | ||
| push!(irreducible_buses, PSY.get_regulated_bus_number(circuit)) | ||
| end |
There was a problem hiding this comment.
I think the convention we're going to go for now is the regulated bus number must always be a valid bus number, so 0 doesn't carry special importance.
That said, I agree maybe we shouldn't be pinning the regulated bus on all controls.
|
@acostarelli I stacked this on top of the PR with the network changes |
ce24265 to
7ebf176
Compare
acostarelli
left a comment
There was a problem hiding this comment.
Implementation review
acostarelli
left a comment
There was a problem hiding this comment.
Tests review
Have not checked that old tap tests that should be ported were ported.
acostarelli
left a comment
There was a problem hiding this comment.
Test port check. Seems fine.
…tage and q bounds
dd4ad35 to
7368dcd
Compare
|
Performance Results
|
| ) | ||
| _control_enabled(_) = false | ||
|
|
||
| _tap_controlled(c::PSY.TransformerControlObjective) = c in ( |
There was a problem hiding this comment.
Not sure how many of these helpers are needed anymore. I wrote them before the RepresentativeBranch refactor
| @@ -184,72 +184,12 @@ end | |||
| # ----------------------------------------------------------------------------- | |||
There was a problem hiding this comment.
I have PFs disabled right now because there was some precompilation error. Haven't looked into it yet. It seemed like something upstream.
| # One entry per transformer arity. Every testset below runs the whole tuple, so the two | ||
| # arities stay in lockstep; `circuit_indices` selects which circuit of the device carries | ||
| # the control objective (the transformer for two-winding, the winding for three-winding). | ||
| const TWO_WINDING_CASE = ( |
There was a problem hiding this comment.
This is kinda verbose, but it works. I also haven't looked into the 3W-specific tests too closely but I think it mostly just reused the 2W tests.
| """ | ||
| Used for specializing the device loop per concrete RepresentativeBranch. | ||
| """ | ||
| function _for_each_branch(f::F, reps) where {F} |
There was a problem hiding this comment.
Closures are unusual for Sienna, but we previously had the issue where the type of the branches we were iterating could've been Lines, MonitoredLines, TwoWindingTransformers, ThreeWindingTransformerCircuits, or some PNM.AbstractReductionAggregate. We need to guard the inner loop by a function so it can specialize.
That said, this is a pretty bare-bones method. Maybe that's okay. Maybe we combine to make _foreach_representative_branch and _foreach_branch ? The issue is a lot of call-sites need the branches vector before iterating so that they can build the names axis for a container, which is an annoying pattern I've encountered several times -- I wish we didn't have to initialize containers with names.
Add support for tap control objectives, and large refactoring of AC_branches.jl